/*
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

package bgtp;

import java.util.*;
import java.lang.*;

public class ASTBuilder
{
    private BGTPLog	log	= null;
    private Scaner	scan	= null;
    private String	tkn	= null;
    private String	errmesg = null;

    private final int	WSTAT  = 1;
    private final int	BBGN   = 2;
    private final int	BEND   = 3;
    private final int	FIN    = 4;
    private final int	DATA   = 5;
    private final int	UMARK  = 6;
    private final int	ERR    = 7;
    private final int	IGNSYM = 8;

    private int		state		= -1;
    private boolean	stop		= false;

    public ASTBuilder()
    {
	scan = new Scaner();
	log  = new BGTPLog("ASTBuilder");
    }

    public ASTNode build(String line)
    {
	ASTNode curt   = new ASTNode(null);
	String	tmpTkn = "";
	tkn	       = "";
	state	       = WSTAT;
	stop	       = false;

	scan.setString(line);

	while(stop == false)
	    { 
		switch(state)
		    {
		    case WSTAT:
			//log.info("build", "WSTAT");
			tmpTkn = scan.getToken();

			if(tmpTkn == null)
			    {
				state = FIN;
				break;
			    }

			tkn += tmpTkn;
			state = whichStatus(tkn);
			
			break;

		    case IGNSYM:
			tkn   = "";
			state = WSTAT;
			break;

		    case BBGN:
			//log.info("build", "BBGN");
			//log.info("build", "token='"+tkn+"'");
			curt  = growth(curt);
			tkn   = "";
			state = WSTAT;
			break;

		    case BEND:
			//log.info("build", "BEND");
			//log.info("build", "token='"+tkn+"'");
			if(curt.back == null)
			    {
				errmesg = "inconsistent ')'";
				state	= ERR;
				break;
			    }
			curt	= curt.back;
			tkn	= "";
			state	= WSTAT;
			break;

		    case FIN:
			//log.info("build", "FIN");
			stop = true;
			break;

		    case ERR:
			//log.info("build", "ERR");
			System.out.println("ERROR: "+errmesg);
			if(curt != null)
			    {
				curt = goToRoot(curt);
				curt.destroy();
				curt = null;
			    }
			state = FIN;
			break;

		    case DATA:
			//log.info("build", "DATA");
			//log.info("build", "token='"+tkn+"'");
			curt	   = growth(curt);
			curt.value = tkn;
			tkn	   = "";
			state	   = WSTAT;
			break;

		    case UMARK: //пометить верхний узел действием
			//log.info("build", "UMARK");
			if(curt.back == null)
			    {
				curt.back = new ASTNode(null);
			    }
			curt = curt.back;
			curt.markNode(tkn);
			//log.info("build", "token='"+tkn+"'");
			tkn	= "";
			state	= WSTAT;
			break;

		    default:
			break;

		    }
	    }

	return goToRoot(curt);
    }

    private ASTNode goToRoot(ASTNode now)
    {
	while(now.back != null)
	    {
		now = now.back;
	    }
	return now;
    }

    private int whichStatus(String token)
    {
	//собираем строки во едино
	if(token.startsWith("'") == true & token.endsWith("'") == false)
	    {
		return WSTAT;
	    }
	
	//если не стрка то пробелы игнорим
	if(token.equals(" ") == true)
	    {
		return IGNSYM;
	    }
	
	if(token.equals("(") == true)
	    {
		return BBGN;
	    }

	if(token.equals(")") == true)
	    {
		return BEND;
	    }

	if(token.equals("!") == true)
	    {
		return WSTAT;
	    }

	if(scan.isTerm(token) == false)
	    {
		return DATA;
	    }

	if(scan.isTerm(token) == true)
	    {
		return UMARK;
	    }
	

	return WSTAT;
    }

    private ASTNode growth(ASTNode node)
    {
	if(node.left == null)
	    {
		node.left = new ASTNode(node);
		return node.left;
	    }
	node.right = new ASTNode(node);
	return node.right;
    }
}